//
//  PingFM.m
//  Pingr
//
//  Created by James Durkee on 5/3/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "PingFM.h"

@implementation PingFM
@synthesize apiKey, userKey;

#pragma mark Initializations

- (id)init {
	self = [super init];
	if (self != nil) {
		[self setValue:API_KEY forKey:@"apiKey"];
	}
	return self;
}
- (id)initWithUserKey:(NSString *)key {
	self = [super init];
	if (self != nil) {
		[self setValue:API_KEY forKey:@"apiKey"];
		[self setUserKey:key];
	}
	return self;
}
- (void)dealloc {
	[userKey release];
	[apiKey release];
	[super dealloc];
}


#pragma mark -
#pragma mark Delegate Setter/Getter

- (void)setDelegate:(id)d {
	delegate = d;
}
- (id)delegate {
	return delegate;
}


#pragma mark -
#pragma mark API Methods

- (BOOL)validate {
	NSMutableDictionary *p = [NSMutableDictionary dictionary];
	[p setObject:userKey forKey:@"user_app_key"];
	[p setObject:apiKey forKey:@"api_key"];
	
	NSXMLDocument *result = [self requestMethod:@"user.validate" parameters:p];
	
	if (!result)
		return NO;
	
	NSXMLNode *statusNode = [[result rootElement] attributeForName:@"status"];
	
	if ([[statusNode objectValue] isEqualToString:@"OK"]) 
		return YES;
	else
		return NO;
}
- (NSArray *)services {
	NSMutableDictionary *p = [NSMutableDictionary dictionary];
	[p setObject:apiKey forKey:@"api_key"];
	[p setObject:userKey forKey:@"user_app_key"];
	
	NSXMLDocument *results = [self requestMethod:@"user.services" parameters:p];
	NSXMLElement *rootElement = [results rootElement];
	NSXMLNode *statusNode = [rootElement attributeForName:@"status"];
	
	if ([[statusNode objectValue] isEqualToString:@"OK"]) {
		NSMutableArray *services = [NSMutableArray array];
		NSArray *xmlServices = [[[rootElement children] objectAtIndex:2] children];
		
		NSLog(@"Services Count: %d", [xmlServices count]);
        
		NSEnumerator *e = [xmlServices objectEnumerator];
		id i;
		while (i = [e nextObject]) {
			NSString *name = [[i attributeForName:@"name"] objectValue];
			NSString *ident = [[i attributeForName:@"id"] objectValue];
			NSString *trigger = [[[i children] objectAtIndex:0] stringValue];
			NSString *serviceURLString = [[[i children] objectAtIndex:1] stringValue];
			NSURL *serviceURL = [NSURL URLWithString:serviceURLString];
			NSString *iconURLString = [[[i children] objectAtIndex:2] stringValue];
			NSURL *iconURL = [NSURL URLWithString:iconURLString];
			NSLog(@"\nName: %@\nTrigger: %@\nService URL: %@\nIcon URL: %@", name, trigger, serviceURLString, iconURLString);
			NSDictionary *serviceEntry = [NSDictionary dictionaryWithObjectsAndKeys:ident, @"ident", name, @"name", trigger, @"trigger", serviceURL, @"serviceURL", iconURL, @"iconURL", nil];
			[services addObject:serviceEntry];
		}
		return services;
	}
	return nil;
}
- (NSArray *)triggers {
	NSMutableDictionary *p = [NSMutableDictionary dictionary];
	[p setObject:apiKey forKey:@"api_key"];
	[p setObject:userKey forKey:@"user_app_key"];
	
	NSXMLDocument *results = [self requestMethod:@"user.triggers" parameters:p];
	NSLog(@"triggers XML: %@", [results stringValue]);
	
	if (!results)
		return nil;
	
	NSXMLElement *rootElement = [results rootElement];
	NSXMLNode *statusNode = [rootElement attributeForName:@"status"];
	
	if ([[statusNode objectValue] isEqualToString:@"OK"]) {
		NSMutableArray *triggers = [NSMutableArray array];
		NSArray *xmlTriggers = [[[rootElement children] objectAtIndex:2] children];
		
		NSLog(@"Triggers Count: %d", [xmlTriggers count]);
		
		NSEnumerator *e = [xmlTriggers objectEnumerator];
		id i;
		while (i = [e nextObject]) {
			NSString *ident = [[i attributeForName:@"id"] objectValue];
			NSString *postMethod = [[i attributeForName:@"method"] objectValue];
			NSLog(@"\nIdent: %@\nMethod: %@", ident, postMethod);
			NSDictionary *triggerEntry = [NSDictionary dictionaryWithObjectsAndKeys:ident, @"ident", postMethod, @"postMethod", nil];
			[triggers addObject:triggerEntry];
		}
		return triggers;
	}
	return nil;
}
- (NSArray *)latest {
	NSMutableDictionary *p = [NSMutableDictionary dictionary];
	[p setObject:apiKey forKey:@"api_key"];
	[p setObject:userKey forKey:@"user_app_key"];
	
	NSXMLDocument *results = [self requestMethod:@"user.latest" parameters:p];
	if (!results) return nil;
	NSXMLElement *rootElement = [results rootElement];
	NSXMLNode *statusNode = [rootElement attributeForName:@"status"];
	
	if ([[statusNode objectValue] isEqualToString:@"OK"]) {
		NSMutableArray *latest = [NSMutableArray array];
		NSArray *xmlLatest = [[[rootElement children] objectAtIndex:2] children];
		
		NSLog(@"Latest Count: %d", [xmlLatest count]);
		
		NSEnumerator *e = [xmlLatest objectEnumerator];
		id i;
		while (i = [e nextObject]) {
			NSString *messageID = [[i attributeForName:@"id"] objectValue];
			NSString *postMethod = [[i attributeForName:@"method"] objectValue];
			double d = [[[[[i children] objectAtIndex:0] attributeForName:@"unix"] objectValue] doubleValue];
			NSDate *date = [NSDate dateWithTimeIntervalSince1970:d];
			//	TODO: Add services, content -> title, body
			
			NSDictionary *latestEntry = [NSDictionary dictionaryWithObjectsAndKeys:messageID, @"id", postMethod, @"postMethod", date, @"date", nil];
			[latest addObject:latestEntry];
		}
		return latest;
	}
	return nil;
}
- (NSArray *)latestWithLimit:(int)limit order:(NSString *)order {
	return nil;
}

#pragma mark -
#pragma mark Post Methods

- (BOOL)simplePost:(NSString *)body withPostMethod:(NSString *)postMethod {
	NSMutableDictionary *p = [NSMutableDictionary dictionary];
	[p setObject:apiKey forKey:@"api_key"];
	[p setObject:userKey forKey:@"user_app_key"];
	[p setObject:postMethod forKey:@"post_method"];
	[p setObject:body forKey:@"body"];
	[p setValue:[NSNumber numberWithInt:DEBUG] forKey:@"debug"];
	
	NSXMLDocument *results = [self requestMethod:@"user.post" parameters:p];
	if (results != nil) {
		NSXMLNode *statusNode = [[results rootElement] attributeForName:@"status"];
		if([[statusNode objectValue] isEqualToString:@"OK"])
			return YES;
	}
	return NO;
}
- (BOOL)simplePost:(NSString *)body withTrigger:(NSString *)trigger {
	NSMutableDictionary *p = [NSMutableDictionary dictionary];
	[p setObject:apiKey forKey:@"api_key"];
	[p setObject:userKey forKey:@"user_app_key"];
	[p setObject:trigger forKey:@"trigger"];
	[p setObject:body forKey:@"body"];
	[p setValue:[NSNumber numberWithInt:DEBUG] forKey:@"debug"];
	
	NSXMLDocument *results = [self requestMethod:@"user.tpost" parameters:p];
	if (results != nil) {
		NSXMLNode *statusNode = [[results rootElement] attributeForName:@"status"];
		if([[statusNode objectValue] isEqualToString:@"OK"])
			return YES;
	}
	return NO;
}
- (BOOL)post:(NSString *)body 
  postMethod:(NSString *)postMethod 
	   title:(NSString *)title 
	 service:(NSString *)service 
	location:(NSString *)location 
	   media:(NSData *)media 
	encoding:(NSString *)encoding 
	 exclude:(NSString *)exclude 
	checksum:(NSString *)checksum {
	
	BOOL success = NO;
	
	NSMutableDictionary *p = [NSMutableDictionary dictionary];
	[p setObject:apiKey forKey:@"api_key"];
	[p setObject:userKey forKey:@"user_app_key"];
	[p setObject:postMethod forKey:@"post_method"];
	if (title)
		[p setObject:title forKey:@"title"];
	if (service)
		[p setObject:service forKey:@"service"];
	if (location)
		[p setObject:location forKey:@"location"];
	if (media)
		[p setObject:media forKey:@"media"];
	if (encoding)
		[p setObject:encoding forKey:@"encoding"];
	if (exclude)
		[p setObject:exclude forKey:@"exclude"];
	if (checksum)
		[p setObject:checksum forKey:@"checksum"];
	[p setValue:[NSNumber numberWithInt:DEBUG] forKey:@"debug"];
	[p setObject:body forKey:@"body"];
	
	NSXMLDocument *results = [self requestMethod:@"user.post" parameters:p];
	if (results != nil) {
		NSXMLNode *statusNode = [[results rootElement] attributeForName:@"status"];
		if([[statusNode objectValue] isEqualToString:@"OK"])
			success = YES;
	}
	return success;
}
- (BOOL)post:(NSString *)body 
 withTrigger:(NSString *)trigger
	   title:(NSString *)title
	location:(NSString *)location 
	   media:(NSData *)media 
	encoding:(NSString *)encoding 
	 exclude:(NSString *)exclude
	checksum:(NSString *)checksum {
		
	BOOL success = NO;
	
	NSMutableDictionary *p = [NSMutableDictionary dictionary];
	[p setObject:apiKey forKey:@"api_key"];
	[p setObject:userKey forKey:@"user_app_key"];
	[p setObject:trigger forKey:@"trigger"];
	if (title)
		[p setObject:title forKey:@"title"];
	if (location)
		[p setObject:location forKey:@"location"];
	if (media)
		[p setObject:media forKey:@"media"];
	if (encoding)
		[p setObject:encoding forKey:@"encoding"];
	if (exclude)
		[p setObject:exclude forKey:@"exclude"];
	if (checksum)
		[p setObject:checksum forKey:@"checksum"];
	[p setValue:[NSNumber numberWithInt:DEBUG] forKey:@"debug"];
	[p setObject:body forKey:@"body"];
	
	NSXMLDocument *results = [self requestMethod:@"user.tpost" parameters:p];
	if (results != nil) {
		NSXMLNode *statusNode = [[results rootElement] attributeForName:@"status"];
		if([[statusNode objectValue] isEqualToString:@"OK"])
			success = YES;
	}
	return success;
}

#pragma mark -
#pragma mark Request Method

/************************** REQUEST METHOD **************************
 *
 * - The request method is generalized and has two arguments, it does all of the work
 *		making HTTP connections, and parsing the XML. It is mainly used internally by the other 
 *		class methods but could be used by the controller if one wanted to manually send 
 *		parameters and parse XML.
 *
 *	ARGUMENTS:
 *		-requestMethod:
 *			- Accepts a string that determines what URL to request from the ping.fm API.
 *			- Examples: user.post, user.validate, user.services, user.latest, etc...
 *
 *		-parameters:
 *			- Accepts a NSMutableDictionary of parameters where the key is equal to the attribute name
 *				and the key's object is equal to the attribute value.
 *
 *	- returns a NSXMLDocument with the XML from the API
 *
 ********************************************************************/

- (NSXMLDocument *)requestMethod:(NSString *)method parameters:(NSMutableDictionary *)parameters {
	//	If the delegate implements requestWillBegin, perform it.
	//		- This can be used to activate a progress indicator, or do any action before the request begins
	if([delegate respondsToSelector:@selector(requestWillBegin)])
		[delegate performSelector:@selector(requestWillBegin)];
	
	//	Set the base of the string that will be used for the final URL and 
	//		append the API method name.
	NSMutableString *pingURLString = [NSMutableString stringWithString:ROOT_URL];
	[pingURLString appendString:method];
	
	//	Create the URL using pingURLString and create a NSMutableURLRequest object
	//		using the URL.  Then set the HTTP method to POST, since all the API methods
	//		are posting methods.
	NSURL *url = [NSURL URLWithString:pingURLString];
	NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
	[request setHTTPMethod:@"POST"];
	
	//	Create a mutable string to place the API parameters in, then enumerate through
	//		the dictionary and prepare the string to be sent
	NSMutableString *parametersString = [NSMutableString string];
	NSEnumerator *e = [parameters keyEnumerator];
	id key;
	while (key = [e nextObject]) {
		[parametersString appendFormat:@"%@=%@&", key, [parameters objectForKey:key]];
	}
	
	//	Set the body of the POST request as the parameterString and encode using UTF8 encoded string
	[request setHTTPBody:[parametersString dataUsingEncoding:NSUTF8StringEncoding]];
	
	//	Create the response and error pointer set to nil
	NSHTTPURLResponse *response = nil;
	NSError *requestError = nil;
	
	//	Create the XML data via a NSURLConnection using the request
	NSData *responseData = [NSURLConnection sendSynchronousRequest:request 
												 returningResponse:&response 
															 error:&requestError];
	//	If there was an error, log it, and forward it to the delegate using the handleError:
	//		delegate method, and return nil to note an error internally
	if (requestError) {
		NSLog(@"Error: %@", [requestError description]);
		if ([delegate respondsToSelector:@selector(handleError:)])
			[delegate performSelector:@selector(handleError:) withObject:requestError];
		if ([delegate respondsToSelector:@selector(requestDidEnd)])
			[delegate performSelector:@selector(requestDidEnd)];
		return nil;
	}
	
	//	Create an XML string called result and initialize it with the responseData
	NSString *result = [[NSString alloc] initWithData:responseData 
											 encoding:NSUTF8StringEncoding];
	//	Create an NSError pointer set to nil for any errors that may occour during parsing
	//		of the XML string into an NSXMLDocument
	NSError *XMLError = nil;
	
	//	Create the NSXMLDocument to be returned
	NSXMLDocument *XMLResult = [[NSXMLDocument alloc] initWithXMLString:result 
																options:10 
																  error:&XMLError];
	//	Release the XML string, we don't need it anymore.
	[result release];
	
	//	Was there an error in parsing the XML?  If there was, log it and message the delegate.
	if (XMLError) {
		NSLog(@"Error: %@", [XMLError description]);
		if ([delegate respondsToSelector:@selector(handleError:)])
			[delegate performSelector:@selector(handleError:) withObject:XMLError];
		if ([delegate respondsToSelector:@selector(requestDidEnd)])
			[delegate performSelector:@selector(requestDidEnd)];
		return nil;
	}
	
	//	If the delegate implements requestDidEnd, perform it
	//		- Can be implemented to end a progress indicator or do any actions after the request has ended
	if ([delegate respondsToSelector:@selector(requestDidEnd)])
		[delegate performSelector:@selector(requestDidEnd)];
	
	return XMLResult;
}

@end
